/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package servlet;

import bdd.Service;
import cipher.MySignature;
import java.io.IOException;
import java.io.PrintWriter;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.gson.Gson;
import java.util.Map;
import servlet.config.Config;

/**
 *
 * @author Alain Janin-Manificat <alain.janinm@hotmail.fr>
 */
@WebServlet(name = "FrontServlet", urlPatterns = {"/index"})
public class FrontServlet extends HttpServlet {

    Service service = null;
    MySignature sign = null;

    @Override
    /**
     * Instanciate the service class with password and user namefrom ServletConfig
     * 
     */
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        Config.setFile(getClass().getClassLoader().getResourceAsStream("servlet/config/config.ini"));
        service = new Service(Config.get("userDB"), Config.get("passwordDB"));
        sign = new MySignature();
    }

    /**
     * Processes requests for both HTTP
     * <code>GET</code> and
     * <code>POST</code> methods.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        try {
            getNextPage(request.getSession().getAttribute("current_page").toString(), request, response);
            RequestDispatcher dispatcher = getServletContext().getRequestDispatcher("/index.jsp");
            dispatcher.forward(request, response);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            out.close();
        }
    }

    /**
     * Get the next view.
     * @param currentPage   String- the current jsp page.
     * @param request       
     * @param response
     * @throws SQLException
     * @throws NoSuchAlgorithmException
     * @throws NoSuchProviderException
     * @throws Exception 
     */
    private void getNextPage(String currentPage, HttpServletRequest request, HttpServletResponse response) throws SQLException, NoSuchAlgorithmException, NoSuchProviderException, Exception {

        if (currentPage.equals("accueil")) {
            getNextPageFromAccueil(request, response);
        }
        else if (currentPage.equals("main")) {
            getNextPageFromMain(request, response);
        }
        else{
            getNextCommonPage(request, response);
        }
//        else {
//            request.setAttribute("current_page", currentPage.toString());
//        }
    }

    // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
    /**
     * Handles the HTTP
     * <code>GET</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Handles the HTTP
     * <code>POST</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Returns a short description of the servlet.
     *
     * @return a String containing servlet description
     */
    @Override
    public String getServletInfo() {
        return "Short description";
    }// </editor-fold>

    /**
     * Get next page from "accueil.jsp".
     * @param request
     * @param response
     * @throws SQLException 
     */
    private void getNextPageFromAccueil(HttpServletRequest request, HttpServletResponse response) throws SQLException {
        
        //Log user
        if (request.getParameter("Login") != null) {
            int idUser;
            if ((idUser = service.logIn(request.getParameter("login"), request.getParameter("password")))!=-1) {
                request.getSession().setAttribute("idUser", idUser);
                request.getSession().setAttribute("login", request.getParameter("login"));
                request.getSession().setAttribute("keys_data", service.getUserCertificates(idUser));
                request.getSession().setAttribute("action", "main.jsp");    //attribute for index.jsp
            } else {
                request.getSession().setAttribute("action", "accueil.jsp");
            }

        } 
        //Register a new user
        else if (request.getParameter("Register") != null) {
            String first_name = (String) request.getParameter("first_name");            //attribute for index.jsp
            String last_name = (String) request.getParameter("last_name");
            String state = (String) request.getParameter("state");
            String login = (String) request.getParameter("login");
            String password = (String) request.getParameter("password");
            String country = (String) request.getParameter("country");
            String company = (String) request.getParameter("company");
           
            try{
                //Insert the new user if "login" is not already in use.
                 if(!service.loginIsExist(login)){
                    int idUser = service.insertRegistration(login, password, first_name, last_name, company, country, state);
                    request.getSession().setAttribute("idUser", idUser);
                    request.getSession().setAttribute("login", login);
                    request.getSession().setAttribute("keys_data", service.getUserCertificates(idUser));
                    request.getSession().setAttribute("action", "main.jsp");
                 }else
                     request.getSession().setAttribute("action", "accueil.jsp");
            }
            catch(Exception e){
                request.getSession().setAttribute("action", "accueil.jsp");
            }            
        }

    }

    /**
     * et next page from "main.jsp".
     * @param request
     * @param response
     * @throws NoSuchAlgorithmException
     * @throws NoSuchProviderException
     * @throws SQLException
     * @throws Exception 
     */
    private void getNextPageFromMain(HttpServletRequest request, HttpServletResponse response) throws NoSuchAlgorithmException, NoSuchProviderException, SQLException, Exception {
        
        if (request.getParameter("action") == null) return;
        if(getNextCommonPage(request, response))return;
        
        //Generate a new par of keys.
        if(request.getParameter("action").equals("generate")){
            
            HashMap<String,String> keys = sign.generateKeys();
            java.sql.Date expDate = java.sql.Date.valueOf(request.getParameter("date"));
            service.insertCertificates((Integer)request.getSession().getAttribute("idUser")
                    , keys.get("private"),keys.get("public"), expDate, false);
            
            request.getSession().setAttribute("keys_data", service.getUserCertificates((Integer)request.getSession().getAttribute("idUser")));
        }
        //Revoke a key.
        else if(request.getParameter("action").contains("revoke")){
            try {
                int id = Integer.parseInt(request.getParameter("action").split(";")[1]);
                service.revokeKey(id);
                request.getSession().setAttribute("keys_data", service.getUserCertificates((Integer)request.getSession().getAttribute("idUser")));
                request.getSession().setAttribute("action", "main.jsp");
            } catch (Exception e) {
                throw e;
            }            
        }
        //Activate a key, the key will appear in the public list of keys.
        else if (request.getParameter("action").contains("activate")){
            try {
                int id = Integer.parseInt(request.getParameter("action").split(";")[1]);
                service.activateCertificate(id);
                request.getSession().setAttribute("keys_data", service.getUserCertificates((Integer)request.getSession().getAttribute("idUser")));
                request.getSession().setAttribute("action", "main.jsp");
            } catch (Exception e) {
                throw e;
            }
        }
        //Delete a key
        else if (request.getParameter("action").contains("delete")){
            try {
                int id = Integer.parseInt(request.getParameter("action").split(";")[1]);
                service.removeKey(id);
                request.getSession().setAttribute("keys_data", service.getUserCertificates((Integer)request.getSession().getAttribute("idUser")));
                request.getSession().setAttribute("action", "main.jsp");
            } catch (Exception e) {
                throw e;
            }
        }
        //Sign a message with selected key.
        else if (request.getParameter("action").contains("sign")){
            try {
                int id = Integer.parseInt(request.getParameter("id"));
                String message = request.getParameter("content");
                String privateKey = service.getPrivateKey(id);
                if(privateKey!=null){
                    String encode = sign.encodeMessage(privateKey, message);
                    String signature = sign.generateSignature(privateKey, encode);
                    
                    Map<String, String> data = new HashMap<String, String>();
                    data.put("encoded_msg", encode);
                    data.put("signature", signature);
                    
                    PrintWriter out = response.getWriter();
                    response.setHeader("Content-type", "application/json");
                    out.write(new Gson().toJson(data));
                    out.flush();
                }
            } catch (Exception e) {
                throw e;
            }
        }
        else {
            request.getSession().setAttribute("action", "accueil.jsp");
        }
        
    }

    /**
     * Get next page from common page (header menu).
     * @param request
     * @param response
     * @return boolean - True if the user action has been procceed, false if nothing has been done.
     * @throws SQLException 
     */
    private boolean getNextCommonPage(HttpServletRequest request, HttpServletResponse response) throws SQLException {
        
        boolean flag = true;
        
        //Display user keys.
        if(request.getParameter("action").equals("yourkeys")){
            request.getSession().setAttribute("keys_data", service.getUserCertificates((Integer)request.getSession().getAttribute("idUser")));
            request.getSession().setAttribute("action", "main.jsp");    //attribute for index.jsp
        }
        //Logoff
        else if (request.getParameter("action").equals("logoff")) {
            try {
                request.getSession().invalidate();
                request.getSession().setAttribute("login", null);
                request.getSession().setAttribute("action", "accueil.jsp");
            } catch (Exception ex) {
                Logger.getLogger(FrontServlet.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        //Display the common list of all public keys.
        else if (request.getParameter("action").contains("publickeys")){           
            request.getSession().setAttribute("action", "publickeys.jsp");
            request.getSession().setAttribute("keys_data", service.getCertificates());
        }
        //Display the common revoked list.
        else if (request.getParameter("action").contains("revokedkeys")){           
            request.getSession().setAttribute("action", "revokedkeys.jsp");
            request.getSession().setAttribute("keys_data", service.getRevokeCertificates());
        }
        else{
            flag=false;
        }
        return flag;
    }
}
